package com.qs.javame.thread1028.blockqueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * 基于阻塞队列（BlockingQueue）实现经典的生产者消费者模型
 */
public class Test {
    public static void main(String[] args) {
        //生产者和消费者公共资源（阻塞队列容量为1，也就意味这生产者生产一个，消费者消费一个，因为线程切换，
        // 实际输出结果打印不是顺序的，但是结果是正确的）
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(1);

        Producer producerTask = new Producer(blockingQueue);
        Consumer consumerTask = new Consumer(blockingQueue);

        //开启一个生产者线程
        new Thread(producerTask).start();
        //开启一个消费者线程
        new Thread(consumerTask).start();

        try {
            Thread.sleep(2000);

            //关闭生产者、消费者线程
            producerTask.shutdown();
            consumerTask.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Producer implements Runnable {

    //阻塞队列作为线程安全的集合，作为多线程之间竞争的公共资源，无需代码同步或者加锁。
    private BlockingQueue<Integer> blockingQueue;

    private volatile boolean flag = false;

    public Producer(BlockingQueue<Integer> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        int i = 1;
        while (!flag) {
            try {
                blockingQueue.put(i);
                System.out.println(Thread.currentThread().getName() + "-生产者生产：i=" + i);
                i = i + 1;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //优雅的结束线程
    public void shutdown() {
        this.flag = true;
    }
}

class Consumer implements Runnable {

    private BlockingQueue<Integer> blockingQueue;

    private volatile boolean flag = false;

    public Consumer(BlockingQueue<Integer> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (!flag) {
            try {
                System.out.println(Thread.currentThread().getName() + "-消费者消费：i=" + blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void shutdown() {
        this.flag = true;
    }
}
